from feedforward import propagate
import backprop
from math import fabs as abs

NEUTRAL = 0.0

def adapt(sequence, encoder, decoder, en_mom, de_mom):
    symbol_size = len(DEFAULT_INPUT)
    coding_size = len(encoder[-1])

    en_preact = [None for s in sequence] # activity (needed for backprop)
    en_postact = [None for s in sequence]
    de_preact = [None for s in sequence]
    de_postact = [None for s in sequence]

    decoding = [None for s in sequence]
    encoding = [DEFAULT_ENCODING] + [None for s in sequence]
    sequence = [DEFAULT_INPUT] * 2 + sequence # add DEFAULT_INPUTS for context at beginning

    # encode
    for n in xrange(len(sequence)-2):
        n_input = encoding[n] + sequence[n] + sequence[n+1] + sequence[n+2]
        (encoding[n+1], en_preact[n], en_postact[n]) = propagate(n_input, encoder)

    encoding = encoding[1:] # take out DEFAULT_ENCODING

    #  perform decoding
    n_input = encoding[-1] + sequence[0] + sequence[1]
    for i in xrange(len(sequence)-2):
        (decoding[i], de_preact[i], de_postact[i]) = propagate(n_input, decoder)
        n_input = decoding[i][symbol_size:] + sequence[i+1] + sequence[i+2]


    # setup first delta... decoding should end with ENDWORD_CODING
    total_error = 0.0
    total_err_i = 0
    errors = []
    for o in xrange(len(ENDWORD_CODING)):
        err_o = decoding[-1][symbol_size:][o] - ENDWORD_CODING[o]
        errors.append(err_o)
        total_error += abs(err_o)
        total_err_i += 1

    deltas = backprop.errors2deltas(errors,de_postact[-1][-1])

    de_postact = [en_postact[-1]] + de_postact
    # backprop decoding
    for i in xrange(1,len(sequence)-1):
        symbol_errors = []
        for s in xrange(symbol_size):
            err_s = sequence[-i][s] - decoding[-i][s]
            symbol_errors.append(err_s)
            total_error += abs(err_s)
            total_err_i += 1

        deltas = backprop.errors2deltas(symbol_errors, de_postact[-i][-1])\
                 + deltas[:coding_size]
        (de_mom, deltas) = backprop.sqrt_backprop_deltas(decoder, deltas, de_preact[-i],\
                      [de_postact[-i-1][-1][:coding_size]] + de_postact[-i], de_mom)

    #backprop encoding
    en_postact = [[[]]] + en_postact
    for n in xrange(1, len(sequence) -1):
        (en_mom, deltas) = backprop.sqrt_backprop_deltas(encoder, deltas, en_preact[-n], [en_postact[-n-1][-1][:coding_size]] + en_postact[-n], en_mom)
        deltas = deltas[:coding_size]

    return (en_mom, de_mom, total_error / total_err_i)


# TODO: let return some kind of error. plot, record, test.
